#ifndef __EX_CHAR_H__
#define __EX_CHAR_H__

#include <linux/sysfs.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
//mmap to user space . to raise frequency.
#include <linux/uio_driver.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/ctype.h>

/* 设备名称 */
#define EXCHAR_DEVICE_NAME        "exchar"
/* IOCTL时的参数(非标准定义方式) */
#define CMD_OP             0x10001

typedef struct {
    char cmd;
    char bank;
    u32  bit;
    u32  val;
} cmd_t;

typedef struct {
    char name[10];
    struct class *cla;
    struct device *dev;
    int major;
} exchar_t;

/* 设备锁 */
static  DEFINE_MUTEX(exchar_mutex);

static char name[40];

/**
 * @brief exchar_attr_cmd_show
 * 		show CMD.
 *
 * @param cla current device class struce.
 * @param attr current device class attrib struct.
 * @param buf return point.
 *
 * @return return buf length.
 */
static ssize_t exchar_attr_cmd_show(struct class *cla, struct class_attribute *attr, char *buf) {
#define CMD_BUFF "This is cmd show..."
	snprintf(buf, strlen(CMD_BUFF) + 1, "%s\n", CMD_BUFF);
    return strlen(buf);
}


/**
 * @brief exchar_attr_cmd_store
 *
 * @param cla current device class struce.
 * @param attr current device class attrib struct.
 * @param buf return point.
 * @param count buf max size.
 *
 * @return If Ok.return count size buf.
 */
static ssize_t exchar_attr_cmd_store(struct class *cla, struct class_attribute *attr, const char *buf, size_t count) {
	mutex_lock(&exchar_mutex);
	snprintf(buf, 40, "[EXCHAR]Store[exchar_attr_cmd_store]\n");
	mutex_unlock(&exchar_mutex);
    return strnlen(buf, count);
}

static ssize_t exchar_attr_keycontrol_show(struct class *cla, struct class_attribute *attr, char *buf) {
	/* 数据直接返回到BUF */
    return snprintf(buf, 40, "[EXCHAR]Show[exchar_attr_keycontrol_show]\n");
}

static ssize_t exchar_attr_keycontrol_store(struct class *cla, struct class_attribute *attr, const char *buf, size_t count) {
	mutex_lock(&exchar_mutex);
	snprintf(buf, 40, "[EXCHAR]Store[exchar_attr_keycontrol_store]\n");
	mutex_unlock(&exchar_mutex);
    return strnlen(buf, count);
}

/* 设备属性.
 * 在/sys/class/exchar 目录下会生成:cmd / keycontrol 2个节点.
 * 读取节点.驱动会调用xxx_show函数.
 * 写入节点.驱动会调用xxx_store函数.
 * 2个函数的参数固定.
 * 设备属性结构必须以__ATTR_NULL结尾.
 */
static struct class_attribute exchar_class_attrs[] = {
    __ATTR(cmd, S_IRUGO | S_IWUSR, exchar_attr_cmd_show, exchar_attr_cmd_store),
    __ATTR(keycontrol, S_IRUGO | S_IWUSR, exchar_attr_keycontrol_show, exchar_attr_keycontrol_store),
    __ATTR_NULL,
};

/* 设备模块.
 * 在/sys/class/exchar 目录下会生成:cmd / keycontrol 2个节点.
 * 读取节点.驱动会调用xxx_show函数.
 * 写入节点.驱动会调用xxx_store函数.
 */
static struct class exchar_class = {
        .name = EXCHAR_DEVICE_NAME,
        .class_attrs = exchar_class_attrs,
    };

//static spinlock_t exchar_lock = SPIN_LOCK_UNLOCKED;

static exchar_t exchar = {
    .cla = NULL,
    .dev = NULL,
    .major = -1,
};

/* UIO结构.
 * 将系统硬件地址映射到用户驱动层.
 */
static struct uio_info exchar_uio_info = {
    .name = "exchar_uio",
    .version = "0.1",
	/* 中断模式.*/
    .irq = UIO_IRQ_NONE,
    .mem = {
        [0] = {
/*
UIO_MEM_NONE	
UIO_MEM_PHYS 映射物理地址.
UIO_MEM_LOGICAL	映射逻辑内存地址.(eg:kmalloc)
UIO_MEM_VIRTUAL 映射虚拟内存地址.
*/
            .memtype = UIO_MEM_NONE,
        },
    },
};
#endif
